package com.nuanshui.heatedloan.service.cms;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;

import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.nuanshui.framework.lang.SysStringUtils;
import com.nuanshui.framework.springContext.SpringContextUtil;
import com.nuanshui.framework.utils.CommonUtil;
import com.nuanshui.heatedloan.constant.TransactionManagerType;
import com.nuanshui.heatedloan.entity.IdEntity;
import com.nuanshui.heatedloan.entity.cms.security.User;
import com.nuanshui.heatedloan.extension.annotation.DefaultSort;
import com.nuanshui.heatedloan.extension.enums.SortType;
import com.nuanshui.heatedloan.extension.exception.CommonSysException;
import com.nuanshui.heatedloan.extension.exception.ParamsErrorException;
import com.nuanshui.heatedloan.extension.exception.ResultCodeException;
import com.nuanshui.heatedloan.extension.jpasearch.Criteria;
import com.nuanshui.heatedloan.extension.jpasearch.Criterion;
import com.nuanshui.heatedloan.extension.jpasearch.Restrictions;
import com.nuanshui.heatedloan.extension.jpasearch.SearchType;
import com.nuanshui.heatedloan.extension.jpasearch.SearchTypeValue;
import com.nuanshui.heatedloan.util.ReflectionUtils;
import com.nuanshui.heatedloan.util.dwz.DwzPage;
import com.nuanshui.heatedloan.util.springdata.PageUtils;

/**
 * 所有的service继承BaseService
 * 
 * 
 *         下午8:17:00
 */
@Transactional(readOnly = true,value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
public class BaseService<T, ID extends Serializable> {

	
	private static int count = 0;
	private JpaRepository<T, ID> jpaRepository;
	private static final ThreadLocal<String> baseUrl = new ThreadLocal<String>();
	private JpaSpecificationExecutor<T> jpaSpecificationExecutor;
	private static final ThreadLocal<User> curUser = new ThreadLocal<User>();
	protected Class<T> entityClass;

	public static void setCurUser(final User user) {
		curUser.set(user);
	}

	public static void setBaseUrl(final String url) {
		baseUrl.set(url);
	}

	@SuppressWarnings("unchecked")
	public BaseService() {
		this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
		final String beanName = getBeanName();

		if (!beanName.startsWith("object") && !beanName.toLowerCase().equals("identitydao")) {
			try {
				final Object obj = SpringContextUtil.getBean(beanName);
				jpaRepository = (JpaRepository<T, ID>) obj;
				jpaSpecificationExecutor = (JpaSpecificationExecutor<T>) obj;
			} catch (final BeansException e) {
				e.printStackTrace();
			}
		}
	}

	private String getBeanName() {
		final String beanName = entityClass.getSimpleName();
		if (beanName.substring(1, 2).matches("[A-Z]")) {
			return beanName + "Dao";
		} else {
			return entityClass.getSimpleName().substring(0, 1).toLowerCase()
					+ entityClass.getSimpleName().substring(1) + "Dao";
		}
	}

	/**
	 * 新增实体
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void save(final T entity) {
		Assert.notNull(entity, "entity不能为空");
		jpaRepository.save(entity);
	}

	/**
	 * 保存一个List
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void save(final List<T> entities) {
		Assert.notNull(entities, "entity不能为空");
		jpaRepository.save(entities);
	}

	/**
	 * 修改实体
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void update(final T entity) {
		Assert.notNull(entity, "entity不能为空");
		jpaRepository.save(entity);
	}

	/**
	 * 删除实体
	 * 
	 * @param entity
	 *            实体对象
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void delete(final T entity) {
		Assert.notNull(entity, "entity不能为空");
		jpaRepository.delete(entity);
	}

	/**
	 * 删除一个实体序列
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void delete(final List<T> entities) {
		Assert.notNull(entities, "entity不能为空");
		jpaRepository.delete(entities);
	}

	/**
	 * 根据id删除实体
	 */
	@Transactional(value=TransactionManagerType.MANAGER_SERVICE_TRANSACTION_MARGER)
	public void delete(final ID id) {
		jpaRepository.delete(id);
	}

	/**
	 * 根据id得到实体
	 */
	public T get(final ID id) {
		Assert.notNull(id, "id不能为空");
		return jpaRepository.findOne(id);
	}

	/**
	 * 查询出某个表的全部内容
	 */
	public List<T> findAll() {
		return jpaRepository.findAll();
	}

	public List<T> findAll(final Sort sort) {
		return jpaRepository.findAll(sort);

	}

	public List<T> findAll(final Object params) {
		return selfFindAll(null, params);
	}

	/**
	 * 分页查询
	 */
	public List<T> findAll(final DwzPage page) {
		final org.springframework.data.domain.Page<T> springDataPage = jpaRepository
				.findAll(PageUtils.createPageable(page));
		PageUtils.injectPageProperties(page, springDataPage);
		return springDataPage.getContent();
	}

	/**
	 * 增加查询条件
	 * 
	 * @param c
	 * @param type
	 *            条件比较的类型
	 * @param fileName
	 *            字段名
	 * @param value
	 *            值
	 * @author 郭浩
	 * @date 2014-9-4
	 */
	private void addParams(final Criteria<T> c, final SearchTypeValue type,
			final String fileName, final Object value, final boolean isJoin) {
		System.out.println(fileName);
		if (SearchTypeValue.EQ == type) {
			c.add(Restrictions.eq(fileName, value, true, isJoin));
		}
		if (SearchTypeValue.GT == type) {
			c.add(Restrictions.gt(fileName, value, true));
		}
		if (SearchTypeValue.GTE == type) {
			c.add(Restrictions.gte(fileName, value, true));
		}
		if (SearchTypeValue.LIKE == type) {
			c.add(Restrictions.like(fileName, value, true));
		}
		if (SearchTypeValue.LT == type) {
			c.add(Restrictions.lt(fileName, value, true, isJoin));
		}
		if (SearchTypeValue.LTE == type) {
			c.add(Restrictions.lte(fileName, value, true, isJoin));
		}
		if (SearchTypeValue.NE == type) {
			c.add(Restrictions.ne(fileName, value, true));
		}
		if (SearchTypeValue.OR == type) {
			String values[] = value.toString().split(",");
			Criterion criterions[] = new Criterion[values.length];

			for (int i = 0; i < values.length; i++) {
				criterions[i] = Restrictions.eq(fileName, values[i], true,
						isJoin);
			}
			c.add(Restrictions.or(criterions));
		}
		if (SearchTypeValue.NOT_IN == type) {
			String values[] = value.toString().split(",");
			for (int i = 0; i < values.length; i++) {
				c.add(Restrictions.ne(fileName, values[i], true));
			}
		}
		if (SearchTypeValue.IN == type) {
			String values[] = value.toString().split(",");
			for (int i = 0; i < values.length; i++) {
				c.add(Restrictions.eq(fileName, values[i], true, isJoin));
			}
		}
	}

	private List<Field> getAllField(final Class clazz) {
		List<Field> fields = new ArrayList<Field>();
		fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
		Class superclass = clazz.getSuperclass();
		if (superclass == IdEntity.class) {
			fields.addAll(Arrays.asList(superclass.getDeclaredFields()));
		}

		return fields;

	}

	public List<T> findAll(final DwzPage page, final Object params) {
		// TODO 剔除重复的对象 暂时不知道用spring data jpa 怎么处理distinct,只能手动剔除
		final List<T> list = selfFindAll(page, params);
		List<T> realList = new ArrayList<T>();
		for (T t : list) {
			if (!realList.contains(t)) {
				realList.add(t);
			}
		}
		// PageUtils.injectPageProperties(page, (long) realList.size());
		return realList;
	}
	
	public List<T> findAllNotDistinct(final DwzPage page, final Object params) {
		// TODO 剔除重复的对象 暂时不知道用spring data jpa 怎么处理distinct,只能手动剔除
		final List<T> list = selfFindAll(page, params);
		// PageUtils.injectPageProperties(page, (long) realList.size());
		return list;
	}

	public List<T> findAll(final DwzPage page, final Object params,
			final boolean distinct) {
		if (distinct) {
			return findAll(page, params);
		} else {
			return selfFindAll(page, params);
		}
	}

	/**
	 * 根据条件进行查询
	 * 
	 * @param page
	 * @param params
	 * @return
	 * @author 郭浩
	 * @date 2014-9-4
	 */
	private List<T> selfFindAll(DwzPage page, final Object params) {
		Class clazz = params.getClass();
		
		List<Field> fields = getAllField(clazz);
		Criteria<T> c = new Criteria<T>();
		Sort relSort = null;
		
		
		boolean isPage = true;
		if (page == null) {
			page = new DwzPage();
			isPage = false;
		}
		for (Field field : fields) {
			/*
			 * 如果没有指定排序方式就使用默认的排序方式
			 */
			if (CommonUtil.isEmpty(page.getOrderField())
					&& field.isAnnotationPresent(DefaultSort.class)) {
				DefaultSort defaultSort = field
						.getAnnotation(DefaultSort.class);
				String fileName = defaultSort.fileName();
				String sort = "";
				if (CommonUtil.isEmpty(fileName)) {
					fileName = field.getName();
				}
				if (SortType.ASC.equals(defaultSort.sort())) {
					sort = DwzPage.ORDER_DIRECTION_ASC;
					relSort = new Sort(Sort.Direction.ASC, fileName);
					
				} else if (SortType.DESC.equals(defaultSort.sort())) {
					sort = DwzPage.ORDER_DIRECTION_DESC;
					relSort = new Sort(Sort.Direction.DESC, fileName);
				}
				//按申请时间倒序排列
//				relSort = new Sort(Sort.Direction.DESC, "createdAt");
				
				page.setOrderField(fileName);
				page.setOrderDirection(sort);
				
				int i=0;
			}
			/**
			 * 判断联合主键里是否有搜索注解
			 */	
			if(field.isAnnotationPresent(EmbeddedId.class)){
//				org.springframework.util.ReflectionUtils.getField(null, null);
//				 Object groupKey = ReflectionUtils.getFieldValue(params, field.getName());
				
				 Object groupKey = ReflectionUtils.invokeGetterMethod(params, field.getName());
				 if(groupKey != null){
					 Field[] fieldArrays = groupKey.getClass().getDeclaredFields();
					 List<Field> innerFields = new ArrayList<Field>(fieldArrays.length);
					 innerFields.addAll(Arrays.asList(fieldArrays));
					 for(Field innerField : innerFields){
						 addParamsByField(innerField, groupKey.getClass(), groupKey, c);	
					 }	 
				 }
			}else{
				/**
				 * 判断普通属性里是否有搜索注解
				 */	
				addParamsByField(field, clazz, params, c);	
			}
			
		}
		if (!isPage) {
			if (relSort == null) {
				return jpaSpecificationExecutor.findAll(c);
			} else {
				return jpaSpecificationExecutor.findAll(c, relSort);
			}

		} else {
			Pageable pg = PageUtils.createPageable(page);
			
			final org.springframework.data.domain.Page<T> springDataPage = 
					jpaSpecificationExecutor.findAll(c, pg);
			PageUtils.injectPageProperties(page, springDataPage);
			return springDataPage.getContent();

		}
	}

	private void addParamsByField(Field field,Class clazz,Object params,Criteria<T> c){
		/**
		 * 判断是否有指定搜索的注解
		 */
		if (field.isAnnotationPresent(SearchType.class)) {
			String name = field.getName();
			SearchType searchType = field.getAnnotation(SearchType.class);
			SearchTypeValue value = searchType.value();
			String child = searchType.child();
			String fileName = searchType.fieldName();
			if (CommonUtil.isEmpty(fileName)) {
				fileName = name;
			}
			/**
			 * 获取属性对应的值
			 */
			try {
				Object object = BeanUtils.getProperty(params, name);
				if (Date.class.isAssignableFrom(field.getType())) {
					String methodName = "get";
					methodName += SysStringUtils.toUpperCase(
							field.getName(), 0, 1);
					Method method = clazz.getMethod(methodName);
					object = method.invoke(params);
				}
				Object childObj = null;
				if (CommonUtil.isNotEmpty(child)) {
					childObj = BeanUtils.getProperty(params, child);
				}
				// 字段的值不为空,并且子类的值为空 ,如果不存在子类，子类的值是空的
				if (CommonUtil.isNotEmpty(object)
						&& CommonUtil.isEmpty(childObj)) {
					addParams(c, value, fileName, object,
							searchType.isJoin());
				}
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
	}
	
	

	/**
	 * 查询对象总数
	 */
	public long count() {
		return jpaRepository.count();
	}

	@Transactional
	public void setStatus(final ID id, final int isvalid) {
		Assert.notNull(id, "id不能为空");
		T t = this.get(id);
		Assert.notNull(t, "内容不存在");
		try {
			BeanUtils.setProperty(t, "isvalid", isvalid);
		} catch (Exception e) {
			e.printStackTrace();
			throw new IllegalArgumentException("操作失败");
		}
		
		
		this.update(t);

	}
	@Transactional
	public void updateOrderNum(ID [] ids) {
		try {
			List<T> ts = new ArrayList<T>();
			for(int i = 0;i<ids.length;i++) {
			   ID id = ids[i];
			   T t = this.get(id);
			   if(t == null) continue;
			   BeanUtils.setProperty(t,"orderNum", i+1);	
			   ts.add(t);
			}
			this.save(ts);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
	}
	/**
	 * 
	 * @Title: deleteFileInContext
	 * @Description: 删除内容中存在链接的图片
	 * @author 郭浩
	 * @param
	 * @return void
	 * @throws
	 * @version V1.0
	 */
	protected void deleteFileInContext(final T entity) {

	}

	protected <T> T error(final String msg) {
		throw new CommonSysException(msg);
	}

	protected void checkNullValue(final Object object,
			final String... filenames) {

		try {
			for (String fileName : filenames) {
				Object obj = BeanUtils.getProperty(object, fileName);
				if (obj == null) {
					throw new ParamsErrorException(fileName);
				}
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}

	}

	protected T errorCode(final String code) {
		throw new ResultCodeException(code);
	}

	/**
	 * 判断不能重复字段数据库中是否以存在
	 * 
	 * @return
	 * @author 郭浩
	 * @date 2014-12-2
	 */
	protected T checkUnique(final Object params, final boolean excluMe) {
		List<Field> fields = getAllField(params.getClass());
		Criteria<T> c = new Criteria<T>();
		List<Criterion> criterions = new ArrayList<Criterion>();
		StringBuilder fieldNames = new StringBuilder();
		try {
			for (Field field : fields) {
				if (field.isAnnotationPresent(Column.class)) {
					Column column = field.getAnnotation(Column.class);
					if (column.unique()) {
						Object object = BeanUtils.getProperty(params,
								field.getName());
						if (object != null) {
							criterions.add(Restrictions.eq(field.getName(),
									object, true, false));
							fieldNames.append(field.getName() + ",");
						}
					}
				}
			}
			c.add(Restrictions.or(criterions));
			if (excluMe) {
				String idValue = BeanUtils.getProperty(params, "id");
				if (idValue != null) {
					c.add(Restrictions.ne("id", idValue, true));
				}
			}
			List<T>  list = jpaSpecificationExecutor.findAll(c);
			if (list.size() > 0) {
				// 已经存在
				if (fieldNames.length() > 0)
					fieldNames = new StringBuilder(fieldNames.substring(0,
							fieldNames.length() - 1));
               return list.get(0);
			}
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return null;
	}
}
